/**
 * Created by user on 2017/12/19.
 */
import { WS_URL } from './config'
import { getSeq, getStamp, Type } from './Global'
import GlobalTime from './GlobalTime'
export default class SocketManager{
  constructor(listener) {
    this.socketMap = {}
    this.socketCount = 0
    this.forceClose = false
    this.listener = Object.assign({}, listener)
    this.pingTimer = null
    this.connectTimer = null
    this.getUserCountTimer = null
  }
  login(options, callback) {
    this.options = Object.assign({}, options)
    if (!this.options.roomId) {
      callback && callback(false)
      return
    }
    this.connect(callback)
  }
  startGetUserTimer() {
    const { m, a } = Type.SEND_TYPE.COMMON_GET_USERS
    this.send({
      m: m,
      a: a,
      s:{
        seq_time: getSeq(),
        timestamp: getStamp()
      },
      d: {}
    })
    this.getUserCountTimer && clearInterval(this.getUserCountTimer)
    this.getUserCountTimer = setInterval(() => {
      const { m, a } = Type.SEND_TYPE.COMMON_GET_USERS
      this.send({
        m: m,
        a: a,
        s:{
          seq_time: getSeq(),
          timestamp: getStamp()
        },
        d: {}
      })
    }, 5 * 1000)
  }
  connect(callback) {
    this.pingTimer && clearInterval(this.pingTimer)
    this.connectTimer && clearTimeout(this.connectTimer)
    this.getUserCountTimer && clearInterval(this.getUserCountTimer)
    var socketObj = this.socketMap['socket_' + this.socketCount]
    if (socketObj) {
      this.socketCount ++
      socketObj.socketTask.close()
      if (!socketObj.callbackDone) {
        socketObj.callback && socketObj.callback()
      }
    }
    var socketTask = new WebSocket(WS_URL)
    this.socketMap['socket_' + this.socketCount] = {
      socketTask: socketTask,
      callback: callback,
      isLogin: false,
      status: 0,
      callbackDone: false
    }
    socketTask.onopen = this.onOpen.bind(this, this.socketCount)
    socketTask.onerror = this.onError.bind(this, this.socketCount)
    socketTask.onclose = this.onClose.bind(this, this.socketCount)
    socketTask.onmessage = this.onMessage.bind(this, this.socketCount)
    this.connectTimer && clearTimeout(this.connectTimer)
    this.connectTimer = setTimeout(() => {
      this.socketMap['socket_' + this.socketCount].callback && this.socketMap['socket_' + this.socketCount].callback(false)
      this.socketMap['socket_' + this.socketCount].callbackDone = true
    }, 5 * 1000)
  }
  onOpen(count, event) {
    if (count != this.socketCount) {
      return
    }
    var id = 'socket_' + this.socketCount
    var socketObj = this.socketMap[id]
    socketObj.status = true
    this.listener.onNotice && this.listener.onNotice({
      code: this.errorCode.CON_SUCCESS.code,
      msg: this.errorCode.CON_SUCCESS.msg,
      info: null
    })
    socketObj.socketTask.send('ping')
    this.pingTimer && clearInterval(this.pingTimer)
    this.pingTimer = setInterval(() => {
      var st = this.socketMap['socket_' + this.socketCount].socketTask
      st.send('ping')
    }, 30 * 1000)
    
  }
  onClose(count, event) {
    if (count != this.socketCount || this.forceClose) {
      return
    }
    this.pingTimer && clearInterval(this.pingTimer)
    this.getUserCountTimer && clearInterval(this.getUserCountTimer)
    var id = 'socket_' + this.socketCount
    this.socketMap[id].status = false
    var socketTask = this.socketMap[id].socketTask
    socketTask.onclose = () => {}
    socketTask.onerror = () => {}
    socketTask.onmessage = () => {}
    socketTask.onopen = () => {}
    if (this.socketMap[id].isLogin) {
      this.listener.onNotice && this.listener.onNotice({
        code: this.errorCode.CON_LOSE.code,
        msg: this.errorCode.CON_LOSE.msg,
        info: {
          socketId: count
        }
      })
    }
  }
  onMessage(count, res) {
    if (count != this.socketCount) {
      return
    }
    var data = {}
    try {
      data = JSON.parse(res.data)
    } catch (e) {}
    if (data.msg_type === Type.INFO_TYPE.MSG_TYPE) {
      if (data.msg_code === Type.INFO_TYPE.SYS_GLOBAL_TIME_NOTICE.msg_code) {
        GlobalTime.setGlobalTime(data.data.timestamp)
      }
      if (data.msg_code === Type.INFO_TYPE.ONLINE_NOTICE.msg_code) {
        this.listener.onNotice && this.listener.onNotice({
          code: this.errorCode.USER_ONLINE.code,
          msg: this.errorCode.USER_ONLINE.msg,
          info: null
        })
        const { m, a } = Type.SEND_TYPE.COMMON_JOIN_ROOM
        this.send({
          m: m,
          a: a,
          s:{
            seq_time: getSeq(),
            timestamp: getStamp()
          },
          d: {
            room_id: this.options.roomId
          }
        })
      }
      if (data.msg_code === Type.INFO_TYPE.SELF_JOIN_ROOM_NOTICE.msg_code) {
        this.listener.onNotice && this.listener.onNotice({
          code: this.errorCode.USER_JOIN_ROOM.code,
          msg: this.errorCode.USER_JOIN_ROOM.msg,
          info: null
        })
        const id = 'socket_' + this.socketCount
        var socketObj = this.socketMap[id]
        socketObj.isLogin = true
        this.connectTimer && clearTimeout(this.connectTimer)

        socketObj.callback && socketObj.callback(true)
        socketObj.callbackDone = true
      }
      this.listener.onNotice && this.listener.onNotice({
        code: this.errorCode.INFO_NOTICE.code,
        msg: this.errorCode.INFO_NOTICE.msg,
        info: data
      })
    } else if (data.msg_type === Type.NOTICE_TYPE.MSG_TYPE) {
      this.listener.onNotice && this.listener.onNotice({
        code: this.errorCode.SYS_NOTICE.code,
        msg: this.errorCode.SYS_NOTICE.msg,
        info: data
      })
    } else if (data.msg_type === Type.ERROR_TYPE.MSG_TYPE) {
      this.listener.onNotice && this.listener.onNotice({
        code: this.errorCode.SYS_ERROR.code,
        msg: this.errorCode.SYS_ERROR.msg,
        info: data
      })
    } else {
      this.listener.onMessage && this.listener.onMessage(data)
    }
  }
  onError(count, event) {
    if (count != this.socketCount) {
      return
    }
  }
  checkSendState() {
    var id = 'socket_' + this.socketCount
    var socketTask = this.socketMap[id].socketTask
    return socketTask.readyState === 1
  }
  send(data) {
    var id = 'socket_' + this.socketCount
    var socketTask = this.socketMap[id].socketTask
    socketTask.send(JSON.stringify(data))
  }
  doClose() {
    this.forceClose = true
    this.pingTimer && clearInterval(this.pingTimer)
    this.connectTimer && clearTimeout(this.connectTimer)
    this.getUserCountTimer && clearInterval(this.getUserCountTimer)
    var id = 'socket_' + this.socketCount
    var socketTask = this.socketMap[id].socketTask
    socketTask.close()
  }
  checkCurrentStatus() {
    var id = 'socket_' + this.socketCount
    var socketTask = this.socketMap[id].socketTask
    return (socketTask.readyState === 1)
  }
  sendTestPing(callback) {
    var id = 'socket_' + this.socketCount
    var socketTask = this.socketMap[id].socketTask
    socketTask.send('ping')
  }
  errorCode = {
    //  连接成功
    CON_SUCCESS: {
      code: 1,
      msg: '连接成功'
    },
    //
    CON_LOSE: {
      code: 2,
      msg: '断开连接, 重连中'
    },
    //  连接失败,
    CON_FAIL: {
      code: 3,
      msg: '连接失败'
    },
    //  重新连接
    CON_RE_SUCCESS: {
      code: 4,
      msg: '重新连接'
    },
    // 上线
    USER_ONLINE: {
      code: 5,
      msg: '上线'
    },
    //  进入房间
    USER_JOIN_ROOM: {
      code: 6,
      msg: '进入房间'
    },
    //  sys error
    SYS_ERROR: {
      code: 7,
      msg: 'sys error'
    },
    //  sys notice
    SYS_NOTICE: {
      code: 8,
      msg: 'sys notice'
    },
    INFO_NOTICE: {
      code: 9,
      msg: 'info notice'
    },
    ROOM_NOT_EXIST: {
      code: 10,
      msg: '房间不存在'
    },
    LOGIN_SUCCESS: {
      code: 11,
      msg: '登录成功'
    },
    LOGIN_TIMEOUT: {
      code: 12,
      msg: '登录超时'
    }
  }
}
